package com.draven.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.draven.common.BusinessException;
import com.draven.entity.FileCategory;
import com.draven.entity.FileInfo;
import com.draven.mapper.FileCategoryMapper;
import com.draven.mapper.FileInfoMapper;
import com.draven.service.FileService;
import com.draven.util.MinioUtil;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 文件服务实现类
 */
@Slf4j
@Service
public class FileServiceImpl implements FileService {

    @Autowired
    private MinioUtil minioUtil;

    @Autowired
    private FileInfoMapper fileInfoMapper;

    @Autowired
    private FileCategoryMapper fileCategoryMapper;

    @Value("${minio.fileSize.image}")
    private Long maxImageSize;

    @Value("${minio.fileSize.document}")
    private Long maxDocumentSize;

    @Value("${minio.fileSize.video}")
    private Long maxVideoSize;

    @Value("${minio.fileSize.audio}")
    private Long maxAudioSize;

    @Value("${minio.fileSize.other}")
    private Long maxOtherSize;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FileInfo uploadFile(MultipartFile file, Long userId, Long categoryId, Integer isPublic) {
        // 检查文件是否为空
        if (file == null || file.isEmpty()) {
            throw new BusinessException(400, "文件不能为空");
        }

        // 检查文件大小
        checkFileSize(file);

        // 获取分类信息
        String categoryName = null;
        if (categoryId != null) {
            FileCategory category = fileCategoryMapper.selectById(categoryId);
            if (category != null && category.getUserId().equals(userId)) {
                categoryName = category.getName();
            } else {
                throw new BusinessException(400, "分类不存在或无权限");
            }
        }

        try {
            // 上传文件到MinIO
            String directory = userId + "/" + getFileTypeDirectory(file);
            Map<String, Object> fileInfo = minioUtil.uploadFile(file, directory);

            // 处理图片缩略图
            String thumbnailUrl = null;
            if (isImageFile(fileInfo.get("fileType").toString())) {
                thumbnailUrl = generateAndUploadThumbnail(file, fileInfo.get("filePath").toString());
            }

            // 保存文件信息到数据库
            FileInfo fileEntity = new FileInfo();
            fileEntity.setUserId(userId);
            fileEntity.setOriginalName(fileInfo.get("originalName").toString());
            fileEntity.setFileName(fileInfo.get("fileName").toString());
            fileEntity.setFilePath(fileInfo.get("filePath").toString());
            fileEntity.setFileUrl(fileInfo.get("fileUrl").toString());
            fileEntity.setFileType(fileInfo.get("fileType").toString());
            fileEntity.setFileSize(Long.parseLong(fileInfo.get("fileSize").toString()));
            fileEntity.setCategoryId(categoryId);
            fileEntity.setCategoryName(categoryName);
            fileEntity.setIsPublic(isPublic);
            fileEntity.setThumbnailUrl(thumbnailUrl);

            fileInfoMapper.insert(fileEntity);
            return fileEntity;
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new BusinessException(500, "文件上传失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<FileInfo> batchUploadFiles(MultipartFile[] files, Long userId, Long categoryId, Integer isPublic) {
        if (files == null || files.length == 0) {
            throw new BusinessException(400, "文件不能为空");
        }

        List<FileInfo> result = new ArrayList<>();
        for (MultipartFile file : files) {
            if (file != null && !file.isEmpty()) {
                try {
                    FileInfo fileInfo = uploadFile(file, userId, categoryId, isPublic);
                    result.add(fileInfo);
                } catch (Exception e) {
                    log.error("批量上传文件失败: {}", e.getMessage());
                    // 继续处理下一个文件
                }
            }
        }
        return result;
    }

    @Override
    public void downloadFile(Long id, Long userId, HttpServletResponse response) {
        FileInfo fileInfo = getFileInfo(id, userId);
        if (fileInfo == null) {
            throw new BusinessException(404, "文件不存在或无权限访问");
        }

        try {
            InputStream inputStream = minioUtil.getFile(fileInfo.getFilePath());
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=" + 
                    new String(fileInfo.getOriginalName().getBytes("UTF-8"), "ISO-8859-1"));
            org.apache.commons.io.IOUtils.copy(inputStream, response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            log.error("文件下载失败", e);
            throw new BusinessException(500, "文件下载失败: " + e.getMessage());
        }
    }

    @Override
    public void previewFile(Long id, Long userId, HttpServletResponse response) {
        FileInfo fileInfo = getFileInfo(id, userId);
        if (fileInfo == null) {
            throw new BusinessException(404, "文件不存在或无权限访问");
        }

        try {
            InputStream inputStream = minioUtil.getFile(fileInfo.getFilePath());
            response.setContentType(fileInfo.getFileType());
            org.apache.commons.io.IOUtils.copy(inputStream, response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            log.error("文件预览失败", e);
            throw new BusinessException(500, "文件预览失败: " + e.getMessage());
        }
    }

    @Override
    public FileInfo getFileInfo(Long id, Long userId) {
        FileInfo fileInfo = fileInfoMapper.selectById(id);
        if (fileInfo == null) {
            return null;
        }

        // 检查权限
        if (!fileInfo.getIsPublic().equals(1) && !fileInfo.getUserId().equals(userId)) {
            return null;
        }

        return fileInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteFile(Long id, Long userId) {
        FileInfo fileInfo = fileInfoMapper.selectById(id);
        if (fileInfo == null) {
            throw new BusinessException(404, "文件不存在");
        }

        // 检查权限
        if (!fileInfo.getUserId().equals(userId)) {
            throw new BusinessException(403, "无权限删除此文件");
        }

        // 删除MinIO中的文件
        minioUtil.deleteFile(fileInfo.getFilePath());

        // 删除数据库记录
        int result = fileInfoMapper.deleteById(id);
        return result > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> batchDeleteFiles(List<Long> ids, Long userId) {
        if (ids == null || ids.isEmpty()) {
            return Collections.emptyList();
        }

        List<Long> successIds = new ArrayList<>();
        for (Long id : ids) {
            try {
                if (deleteFile(id, userId)) {
                    successIds.add(id);
                }
            } catch (Exception e) {
                log.error("删除文件失败: {}", e.getMessage());
                // 继续处理下一个文件
            }
        }
        return successIds;
    }

    @Override
    public List<FileInfo> getFileList(Long userId, Long categoryId, String fileType, String keyword) {
        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileInfo::getUserId, userId);

        if (categoryId != null) {
            queryWrapper.eq(FileInfo::getCategoryId, categoryId);
        }

        if (StringUtils.isNotBlank(fileType)) {
            queryWrapper.like(FileInfo::getFileType, fileType);
        }

        if (StringUtils.isNotBlank(keyword)) {
            queryWrapper.and(wrapper -> wrapper
                    .like(FileInfo::getOriginalName, keyword)
                    .or()
                    .like(FileInfo::getFileName, keyword));
        }

        queryWrapper.orderByDesc(FileInfo::getCreateTime);
        return fileInfoMapper.selectList(queryWrapper);
    }

    @Override
    public boolean updateFileInfo(FileInfo fileInfo) {
        // 检查文件是否存在
        FileInfo existFileInfo = fileInfoMapper.selectById(fileInfo.getId());
        if (existFileInfo == null) {
            throw new BusinessException(404, "文件不存在");
        }

        // 检查权限
        if (!existFileInfo.getUserId().equals(fileInfo.getUserId())) {
            throw new BusinessException(403, "无权限修改此文件");
        }

        // 更新分类信息
        if (fileInfo.getCategoryId() != null && !fileInfo.getCategoryId().equals(existFileInfo.getCategoryId())) {
            FileCategory category = fileCategoryMapper.selectById(fileInfo.getCategoryId());
            if (category != null && category.getUserId().equals(fileInfo.getUserId())) {
                fileInfo.setCategoryName(category.getName());
            } else {
                throw new BusinessException(400, "分类不存在或无权限");
            }
        }

        // 保留不可修改的字段
        fileInfo.setFileName(existFileInfo.getFileName());
        fileInfo.setFilePath(existFileInfo.getFilePath());
        fileInfo.setFileUrl(existFileInfo.getFileUrl());
        fileInfo.setFileType(existFileInfo.getFileType());
        fileInfo.setFileSize(existFileInfo.getFileSize());
        fileInfo.setThumbnailUrl(existFileInfo.getThumbnailUrl());

        int result = fileInfoMapper.updateById(fileInfo);
        return result > 0;
    }

    @Override
    public Map<String, Object> getFileStats(Long userId) {
        Map<String, Object> stats = new HashMap<>();

        // 获取文件总数
        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileInfo::getUserId, userId);
        Long totalCount = fileInfoMapper.selectCount(queryWrapper);
        stats.put("totalCount", totalCount);

        // 获取不同类型文件数量
        Map<String, Integer> typeStats = new HashMap<>();
        List<FileInfo> fileList = fileInfoMapper.selectList(queryWrapper);

        // 统计不同文件类型的数量
        for (FileInfo fileInfo : fileList) {
            String type = getSimpleFileType(fileInfo.getFileType());
            typeStats.put(type, typeStats.getOrDefault(type, 0) + 1);
        }
        stats.put("typeStats", typeStats);

        // 统计总文件大小
        long totalSize = fileList.stream().mapToLong(FileInfo::getFileSize).sum();
        stats.put("totalSize", totalSize);

        // 按分类统计
        Map<String, Integer> categoryStats = fileList.stream()
                .filter(file -> file.getCategoryId() != null)
                .collect(Collectors.groupingBy(
                        file -> file.getCategoryName() != null ? file.getCategoryName() : "未分类",
                        Collectors.summingInt(file -> 1)
                ));
        stats.put("categoryStats", categoryStats);

        return stats;
    }

    /**
     * 检查文件大小
     * @param file 文件
     */
    private void checkFileSize(MultipartFile file) {
        long size = file.getSize();
        String contentType = file.getContentType();

        if (contentType != null) {
            if (contentType.startsWith("image/")) {
                if (size > maxImageSize) {
                    throw new BusinessException(400, "图片大小不能超过" + (maxImageSize / 1024 / 1024) + "MB");
                }
            } else if (contentType.startsWith("video/")) {
                if (size > maxVideoSize) {
                    throw new BusinessException(400, "视频大小不能超过" + (maxVideoSize / 1024 / 1024) + "MB");
                }
            } else if (contentType.startsWith("audio/")) {
                if (size > maxAudioSize) {
                    throw new BusinessException(400, "音频大小不能超过" + (maxAudioSize / 1024 / 1024) + "MB");
                }
            } else if (contentType.contains("pdf") || contentType.contains("document") || 
                    contentType.contains("msword") || contentType.contains("officedocument")) {
                if (size > maxDocumentSize) {
                    throw new BusinessException(400, "文档大小不能超过" + (maxDocumentSize / 1024 / 1024) + "MB");
                }
            } else if (size > maxOtherSize) {
                throw new BusinessException(400, "文件大小不能超过" + (maxOtherSize / 1024 / 1024) + "MB");
            }
        } else if (size > maxOtherSize) {
            throw new BusinessException(400, "文件大小不能超过" + (maxOtherSize / 1024 / 1024) + "MB");
        }
    }

    /**
     * 判断是否为图片文件
     * @param contentType 内容类型
     * @return 是否为图片
     */
    private boolean isImageFile(String contentType) {
        return contentType != null && contentType.startsWith("image/");
    }

    /**
     * 根据文件类型获取存储目录
     * @param file 文件
     * @return 目录名
     */
    private String getFileTypeDirectory(MultipartFile file) {
        String contentType = file.getContentType();
        if (contentType != null) {
            if (contentType.startsWith("image/")) {
                return "images";
            } else if (contentType.startsWith("video/")) {
                return "videos";
            } else if (contentType.startsWith("audio/")) {
                return "audios";
            } else if (contentType.contains("pdf") || contentType.contains("document") || 
                    contentType.contains("msword") || contentType.contains("officedocument")) {
                return "documents";
            }
        }
        return "others";
    }

    /**
     * 获取简化的文件类型
     * @param contentType 内容类型
     * @return 简化类型
     */
    private String getSimpleFileType(String contentType) {
        if (contentType != null) {
            if (contentType.startsWith("image/")) {
                return "image";
            } else if (contentType.startsWith("video/")) {
                return "video";
            } else if (contentType.startsWith("audio/")) {
                return "audio";
            } else if (contentType.contains("pdf") || contentType.contains("document") || 
                    contentType.contains("msword") || contentType.contains("officedocument")) {
                return "document";
            }
        }
        return "other";
    }

    /**
     * 生成并上传缩略图
     * @param file 原始文件
     * @param objectName 对象名称
     * @return 缩略图URL
     */
    private String generateAndUploadThumbnail(MultipartFile file, String objectName) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            Thumbnails.of(file.getInputStream())
                    .size(200, 200)
                    .outputFormat("jpg")
                    .outputQuality(0.8)
                    .toOutputStream(outputStream);

            byte[] thumbnailBytes = outputStream.toByteArray();
            ByteArrayInputStream inputStream = new ByteArrayInputStream(thumbnailBytes);
            
            return minioUtil.uploadThumbnail(inputStream, thumbnailBytes.length, objectName);
        } catch (IOException e) {
            log.error("生成缩略图失败", e);
            return null;
        }
    }
} 